﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using Common.Utility;
using GalaSoft.MvvmLight;

namespace Common.ViewModel
{
   public class WellBase: ObservableObject, IWell
   {
      public WellBase()
      {
      }

      /// <summary>
      /// The <see cref="Title" /> property's name.
      /// </summary>
      public const string TitlePropertyName = "Title";

      protected string _Title = "";

      /// <summary>
      /// Sets and gets the Title property.
      /// Changes to that property's value raise the PropertyChanged event. 
      /// </summary>
      public string Title
      {
         get
         {
            return _Title;
         }
         set
         {
            if (_Title == value)
            {
               return;
            }

            _Title = value;
            RaisePropertyChanged(TitlePropertyName);
         }
      }

      /// <summary>
      /// The <see cref="Visible" /> property's name.
      /// </summary>
      public const string VisiblePropertyName = "Visible";

      private bool _Visible = true;

      /// <summary>
      /// Sets and gets the Visible property.
      /// Changes to that property's value raise the PropertyChanged event. 
      /// </summary>
      public bool Visible
      {
         get
         {
            return _Visible;
         }

         set
         {
            if (_Visible == value)
            {
               return;
            }

            _Visible = value;
            RaisePropertyChanged(VisiblePropertyName);
         }
      }

      /// <summary>
      /// The <see cref="Color" /> property's name.
      /// </summary>
      public const string ColorPropertyName = "Color";

      private Color _Color = new Color();

      /// <summary>
      /// Sets and gets the Color property.
      /// Changes to that property's value raise the PropertyChanged event. 
      /// </summary>
      public Color Color
      {
         get
         {
            return _Color;
         }

         set
         {
            if (_Color == value)
            {
               return;
            }

            _Color = value;
            RaisePropertyChanged(ColorPropertyName);
         }
      }

      /// <summary>
      /// The <see cref="Focus" /> property's name.
      /// </summary>
      public const string FocusPropertyName = "Focus";

      private FocusLevels _Focus = FocusLevels.Normal;

      /// <summary>
      /// Sets and gets the Focus property.
      /// Changes to that property's value raise the PropertyChanged event. 
      /// </summary>
      public FocusLevels Focus
      {
         get
         {
            return _Focus;
         }

         set
         {
            if (_Focus == value)
            {
               return;
            }

            _Focus = value;
            RaisePropertyChanged(FocusPropertyName);
         }
      }
   }

   public class WellBaseComparer : ICustomSorter
   {
      private string _SortMemberPath = "";

      public string SortMemberPath
      {
         get
         {
            return _SortMemberPath;
         }

         set
         {
            _SortMemberPath = value;
         }
      }

      private bool GetValues(string prop, Type currentType, object left, object right, out object nextLeft, out object nextRight)
      {
         nextLeft = null;
         nextRight = null;

         int nextBracket = prop.IndexOf('[');

         PropertyInfo propInfo = null;
         string index = "";

         if (nextBracket != -1)
         {
            string[] splitUp = prop.Split(new char[2] { '[', ']' }, StringSplitOptions.RemoveEmptyEntries);

            prop = prop.Substring(0, nextBracket);

            if (splitUp.Length != 2)
               return false;

            index = splitUp[1];
         }

         propInfo = currentType.GetProperty(prop);

         if (propInfo != null)
         {
            nextLeft = propInfo.GetValue(left);
            nextRight = propInfo.GetValue(right);

            if (nextBracket != -1)
            {
               left = nextLeft;
               right = nextRight;

               //find the get_Item member and see what the passed type is
               var getMember = propInfo.PropertyType.GetMethod("get_Item");

               if (getMember == null)
                  return false;

               var parameters = getMember.GetParameters();

               if (parameters.Length != 1)
                  return false;

               object[] indexParam = new object[1];

               if (parameters[0].ParameterType == typeof(Int32))
               {
                  indexParam[0] = Int32.Parse(index);
               }
               else if (parameters[0].ParameterType == typeof(Double))
               {
                  indexParam[0] = Double.Parse(index);
               }
               else if (parameters[0].ParameterType == typeof(String))
               {
                  indexParam[0] = index;
               }
               else
               {
                  return false;
               }

               nextLeft = getMember.Invoke(left, indexParam);
               nextRight = getMember.Invoke(right, indexParam);
            }

            return true;
         }
         else
         {
            return false;
         }
      }

      private int TestProperty(string prop, Type currentType, object left, object right)
      {
         int nextDot = prop.IndexOf('.');

         object nextLeft = null;
         object nextRight = null;

         if (nextDot != -1)
         {
            string nextProp = prop.Substring(0, nextDot);

            if (!GetValues(nextProp, currentType, left, right, out nextLeft, out nextRight))
               return 0;

            return TestProperty(prop.Substring(nextDot + 1), nextLeft.GetType(), nextLeft, nextRight);
         }

         if (!GetValues(prop, currentType, left, right, out nextLeft, out nextRight))
            return 0;

         IComparable leftC = nextLeft as IComparable;
         IComparable rightC = nextRight as IComparable;

         if (leftC != null && rightC != null)
         {
            return leftC.CompareTo(rightC);
         }
         else
         {
            return 0;
         }
      }

      public int Compare(object x, object y)
      {
         WellBase left = x as WellBase;
         WellBase right = y as WellBase;

         int i = 0;

         if (left.Visible == right.Visible)
         {
            //Evaluate strings
            i = TestProperty(SortMemberPath, typeof(WellBase), left, right);
         }
         else
         {
            if (left.Visible)
            {
               return -1;
            }
            else
            {
               return 1;
            }
         }

         if (SortDirection == ListSortDirection.Ascending)
            return i;

         return i * -1;
      }

      public ListSortDirection SortDirection
      {
         get; set;
      }
   }
}
